import time

from datastructure.link import list
from threading import Condition, Lock


class Queueempty(BaseException):
    pass


class Queuefull(BaseException):
    pass


class Queue:
    def __init__(self, maxsize):
        self.maxsize = maxsize
        self._queue = list()
        self._lock = Lock()
        self._read_lock = Condition(self._lock)
        self._write_lock = Condition(self._lock)

    def _is_full(self):
        return self._queue == self.maxsize

    def _is_empty(self):
        return self._queue == 0

    def get(self, block=True):
        self._read_lock.acquire()
        try:
            while self._is_empty():
                Queue.__notify(self._write_lock)
                if block:
                    self._read_lock.wait()
                else:
                    raise Queueempty
            data = self._queue.pop()
            Queue.__notify(self._write_lock)
        finally:
            self._read_lock.release()
        return data

    @staticmethod
    def __notify(condition, time_to_sleep=0.00001):

        condition.notify()
        time.sleep(time_to_sleep)

    def put(self, data, block=False):
        self._write_lock.acquire()
        try:
            while self._is_full():
                Queue.__notify(self._read_lock)
                if block:
                    self._write_lock.wait()
                else:
                    raise Queuefull
            self._queue.append(data)
            Queue.__notify(self._read_lock)
        finally:
            self._write_lock.release()


if __name__ == '__main__':
    import threading
    import threadpool

    queue = Queue(maxsize=10)
    threads = threadpool.ThreadPool(10)


    def wait_request_to_process():
        thread_id = threading.current_thread().ident
        while True:
            data = queue.get(block=True)
            print("{} output: {}".format(thread_id, data))


    for t in range(10):
        request = threadpool.WorkRequest(callable_=wait_request_to_process)
        threads.putRequest(request)

    import random

    while True:
        d = random.randint(1, 10000)
        try:
            queue.put(d, block=True)
        except:
            pass
